/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/*!
  \file			txlist.cc
  \date			Feb 2012
  \author		TNick

  \brief		Contains the implementation of TxList class


*//*


 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Please read COPYING and README files in root folder
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
//
//
//
//
/*  INCLUDES    ------------------------------------------------------------ */

#include	<stdlib.h>

#include	<QString>

#include	<objdeflib_internal.h>

#include	<session.h>

#include	"txlist.h"


/*  INCLUDES    ============================================================ */
//
//
//
//
/*  DEFINITIONS    --------------------------------------------------------- */


/*  DEFINITIONS    ========================================================= */
//
//
//
//
/*  DATA    ---------------------------------------------------------------- */

/*  DATA    ================================================================ */
//
//
//
//
/*  CLASS    --------------------------------------------------------------- */

/* ------------------------------------------------------------------------- */
TxList::TxList	( void )
{
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
TxList::~TxList	( void )
{
	clear();
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void			TxList::clear			( void )
{
	for ( int i = 0; i < names_.count(); i++ )
	{
		free( names_.at( i ) );
	}
	names_.clear();
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
QChar *			TxList::append			( unsigned & index, QString s_tx )
{
	return append( s_tx, index );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
QChar *			TxList::append			( QString & s_tx, unsigned & index )
{
	index = 0;

	/* get the size */
	QString::const_iterator ci_s = s_tx.begin();
	QString::const_iterator ci_e = s_tx.end();
	unsigned sz = ci_e - ci_s + EXTRA_CHARS;
	unsigned sz_b = sz * sizeof( QChar );
	if ( sz_b > (0xFFFF ) ) return NULL;

	QChar * ret_b = (QChar*)malloc( sz_b );
	if ( ret_b == NULL ) return NULL;

	/* copy the content */
	memcpy( ret_b + HEADER_SIZE, ci_s, sz_b);

	/* place ending NULL */
	*(ret_b + sz - 1) = 0;

	/* save the lenght */
	setCharLen( ret_b, ci_e - ci_s );

	/* save the reference count = 1 */
	setChRefCount( ret_b, 1 );

	/* add it to list */
	Q_ASSERT( isCharNullTerminated( ret_b ) );
	index = (unsigned)names_.count( );
	names_.append( ret_b );

	return ret_b;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
QChar *			TxList::append			(
		const char * p_s_tx, unsigned & index )
{
	QString s( p_s_tx );
	return append( s, index );
}
/* ========================================================================= */


/* ------------------------------------------------------------------------- */
QChar *			TxList::find			( QString & s_tx, unsigned & index )
{
	QChar * itr_ch ;
	unsigned s_len = s_tx.length();
	QChar * itr_s;
	unsigned i; unsigned j;

	for ( i = 0; i < (unsigned)names_.length(); i++ )
	{
		itr_ch = names_.at( i );
		if ( charLen( itr_ch ) == s_len )
		{
			itr_ch += IDX_STR;
			itr_s = s_tx.begin();
			for ( j = 0; j < s_len; j++ )
			{
				if ( itr_s[j] != itr_ch[j] )
				{
					break;
				}
			}
			itr_ch -= IDX_STR;
			if ( j == s_len )
			{
				index = i;
				return itr_ch;
			}
		}
	}
	index = 0;
	return NULL;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
QChar *			TxList::find			(
		const char * s_tx, unsigned & index, int s_len )
{
	index = 0;
	if ( s_tx == NULL )
		return NULL;

	if ( s_len == -1 )
	{
		s_len = strlen( s_tx );
	}


	QChar * itr_ch ;
	unsigned i; unsigned j;

	for ( i = 0; i < (unsigned)names_.length(); i++ )
	{
		itr_ch = names_.at( i );
		if ( charLen( itr_ch ) == (unsigned)s_len )
		{
			itr_ch += IDX_STR;
			for ( j = 0; j < (unsigned)s_len; j++ )
			{
				if ( s_tx[j] != itr_ch[j] )
				{
					break;
				}
			}
			itr_ch -= IDX_STR;
			if ( j == (unsigned)s_len )
			{
				index = i;
				return itr_ch;
			}
		}
	}
	index = 0;
	return NULL;

}
/* ========================================================================= */


/* ------------------------------------------------------------------------- */
QChar *			TxList::addUniq			( QString & s_tx, unsigned & index )
{

	QChar * ret_v = find( s_tx, index );
	if ( ret_v == NULL )
	{
		return append( s_tx, index );
	}
	return ret_v;
}
/* ========================================================================= */


/* ------------------------------------------------------------------------- */
QChar *			TxList::addUniq			(
		const char * p_s_tx, unsigned & index )
{

	QChar * ret_v = find( p_s_tx, index );
	if ( ret_v == NULL )
	{
		return append( p_s_tx, index );
	}
	return ret_v;

}
/* ========================================================================= */








#ifdef	OBJECTSLIB_TESTS

#define ONE_TEST_STRING		"some random text here"
#define OTS_SIZE ( sizeof(ONE_TEST_STRING) - 1 )
#define SECOND_TEST_STRING	"some other text here"


/* ------------------------------------------------------------------------- */
void				TxList_Tests_with_one					(
		int & performed, int & succeded,
		TxList * txl,	unsigned & idx_res, QChar * res_p,
		const char * comment  )
{
	QString		Outcm;
	bool		b_ok = false;

	for (;;)	{
		if ( txl->at( 0 ) == NULL ) break;
		if ( txl->at( 1 ) != NULL ) break;
		if ( txl->at( -1 ) != NULL ) break;
		if ( txl->at( 10 ) != NULL ) break;
		if ( txl->at( 100 ) != NULL ) break;
		if ( txl->at( 1000 ) != NULL ) break;

		if ( txl->at( 0 ) != res_p ) break;
		if ( idx_res != 0 ) break;

		if ( txl->count() != 1 ) break;

		if ( txl->index( res_p ) != 0 ) break;
		if ( txl->index( NULL ) != -1 ) break;

		if ( txl->refCount( res_p ) != 1 ) break;
		txl->incRef( res_p );
		if ( txl->refCount( idx_res ) != 2 ) break;
		txl->incRef( idx_res );
		if ( txl->refCount( res_p ) != 3 ) break;
		txl->decRef( idx_res );
		if ( txl->refCount( res_p ) != 2 ) break;
		txl->decRef( res_p );
		if ( txl->refCount( idx_res ) != 1 ) break;

		if ( txl->getSize( res_p ) != OTS_SIZE ) break;
		if ( txl->getSize( idx_res ) != OTS_SIZE ) break;

		if ( txl->asArray( res_p ) != res_p + IDX_STR )  break;
		if ( txl->asArray( idx_res ) != res_p + IDX_STR )  break;

		if ( txl->asString( res_p ) != ONE_TEST_STRING )  break;
		if ( txl->asString( idx_res ) != ONE_TEST_STRING )  break;


		b_ok = true; break;
	}
	TEST_RESULT( b_ok, comment );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void				TxList_Tests_with_none					(
		int & performed, int & succeded,
		TxList * txl, const char * comment  )
{
	QString		Outcm;
	bool		b_ok = false;

	for (;;)	{
		if ( txl->at( 0 ) != NULL ) break;
		if ( txl->at( 1 ) != NULL ) break;
		if ( txl->at( -1 ) != NULL ) break;
		if ( txl->at( 10 ) != NULL ) break;
		if ( txl->at( 100 ) != NULL ) break;
		if ( txl->at( 1000 ) != NULL ) break;

		if ( txl->count() != 0 ) break;

		if ( txl->index( (QChar*)NULL ) != -1 ) break;

		if ( txl->asArray( (QChar*)NULL ) != NULL )  break;
		if ( txl->asArray( (unsigned)0 ) != NULL )  break;
		if ( txl->asArray( 10 ) != NULL )  break;
		if ( txl->asArray( 100 ) != NULL )  break;

		if ( txl->asString( (QChar*)NULL ).isEmpty() == false )  break;
		if ( txl->asString( (unsigned)0 ).isEmpty() == false )  break;
		if ( txl->asString( 10 ).isEmpty() == false )  break;
		if ( txl->asString( 100 ).isEmpty() == false )  break;

		b_ok = true; break;
	}
	TEST_RESULT( b_ok, comment );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void				TxList_Tests					(
		int & performed, int & succeded )
{
	QString		Outcm;
	performed = 0;
	succeded = 0;
	bool		b_ok;
	unsigned	idx_res;
	QChar *		res_p;
	QChar *		res_p2;

	TEST_RESULT( sizeof(QChar) == 2, "Assumed char size" );

	TxList * txl = new TxList();

	TxList_Tests_with_none( performed, succeded, txl,
							"Testing initial state");

	res_p = txl->append( ONE_TEST_STRING, idx_res );
	TxList_Tests_with_one( performed, succeded, txl, idx_res, res_p,
							"One element from const char *");
	txl->bfRemove( res_p );
	TxList_Tests_with_none( performed, succeded, txl,
							"One removed with pointer");

	res_p = txl->append( idx_res, QString( ONE_TEST_STRING ) );
	TxList_Tests_with_one( performed, succeded, txl, idx_res, res_p,
							"One element from const QString");
	txl->bfRemove( idx_res );
	TxList_Tests_with_none( performed, succeded, txl,
							"One removed with index");
	QString	s_t( ONE_TEST_STRING );
	res_p = txl->append( s_t, idx_res );
	TxList_Tests_with_one( performed, succeded, txl, idx_res, res_p,
							"One element from const QString &");
	txl->clear( );
	TxList_Tests_with_none( performed, succeded, txl,
							"One removed with clear");


	/* create a raw structure and see if it works */
	QChar * chb = (QChar *)malloc(
				( OTS_SIZE + EXTRA_CHARS ) *
				sizeof( QChar ) );
	const char * p_ch = ONE_TEST_STRING;
	chb[IDX_REFCOUNT] = 1; /* reference count */
	chb[IDX_LEN] = (int)OTS_SIZE; /* string lenght */
	for ( unsigned i = 0; i < OTS_SIZE; i++ )
	{
		chb[IDX_STR+i] = p_ch[i];
	}
	chb[IDX_STR+OTS_SIZE] = 0; /* terminating character */


	res_p = chb;
	idx_res = txl->append( chb );
	TxList_Tests_with_one( performed, succeded, txl, idx_res, res_p,
							"One element from QChar array");
	txl->bfRemove( res_p );
	TxList_Tests_with_none( performed, succeded, txl,
							"One removed with pointer");

	unsigned test_len = 1000;
	unsigned i;
	unsigned out_f;
	for ( i = 0; i < test_len; i++ )
	{
		txl->append( idx_res, QString::number( i ) );
		if ( idx_res != i ) break;
	}
	TEST_RESULT( i == test_len, "Adding numerous items" );

	for ( i = 0; i < test_len; i++ )
	{
		if ( txl->asString( i ) != QString::number( i ) )
			break;
		res_p = txl->at( i );
		if ( res_p == NULL )
			break;
		if ( (unsigned)txl->index( res_p ) != i )
			break;

		if ( txl->find( out_f, QString::number( i ) )  != res_p ) break;
		if ( out_f != i ) break;
		if ( txl->addUniq( out_f, QString::number( i ) )  != res_p ) break;
		if ( out_f != i ) break;
	}
	TEST_RESULT( i == test_len, "Getting the string back" );

	txl->clear( );
	TxList_Tests_with_none( performed, succeded, txl,
							"Many removed with clear");


	for (;;)	{

		res_p = txl->addUniq( idx_res, QString( ONE_TEST_STRING ) );
		if ( res_p == NULL ) break;
		if ( idx_res != 0) break;
		res_p2 = txl->addUniq( idx_res, QString( SECOND_TEST_STRING ) );
		if ( res_p2 == NULL ) break;
		if ( idx_res != 1) break;

		if ( res_p != txl->addUniq( idx_res, QString( ONE_TEST_STRING ) ) )
			break;
		if ( idx_res != 0) break;
		if ( res_p2 == txl->addUniq( idx_res, QString( SECOND_TEST_STRING ) ) )
			break;
		if ( idx_res != 1) break;


		b_ok = true; break;
	}
	TEST_RESULT( b_ok, "appendOne and related" );


	delete txl;

}
/* ========================================================================= */

#endif



/*  CLASS    =============================================================== */
//
//
//
//
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
